/*
** $Id: ltm.h $
** 元方法
** See Copyright Notice in lua.h
*/

#ifndef ltm_h
#define ltm_h


#include "lobject.h"
#include "lstate.h"


/*
* 警告: 如果改变这个枚举的顺序，请查找 "ORDER TM" 和 "ORDER OP"
*/
typedef enum {
  TM_INDEX, // __index(obj, key) return res end  访问不存在的字段时调用
  TM_NEWINDEX,  // __newindex(obj, key, value)  赋值新字段时调用
  TM_GC,  // __gc(obj)
  TM_MODE,  // __mode = "k" 或 "v" 或 "kv" 弱性(弱键/弱值/弱键值)
  TM_LEN,   // __len(obj) return res end  #
  TM_EQ,  /* __eq == 具有快速访问的最后一个元方法 */
  TM_ADD, // __add(obj1, obj2) return res end  +
  TM_SUB, // __sub(obj1, obj2) return res end  -
  TM_MUL, // __mul(obj1, obj2) return res end  *
  TM_MOD, // __mod(obj1, obj2) return res end  %
  TM_POW, // __pow(obj1, obj2) return res end  ^
  TM_DIV, // __div(obj1, obj2) return res end  /
  TM_IDIV,  // __idiv(obj1, obj2) return res end   //(取整触发)
  TM_BAND,  // __band(obj1, obj2) return res end   &
  TM_BOR, // __bor(obj1, obj2) return res end      |
  TM_BXOR,  // __bxor(obj1, obj2) return res end   ~
  TM_SHL, // __shl(obj1, obj2) return res end      <<
  TM_SHR, // __shr(obj1, obj2) return res end      >>
  TM_UNM, // __unm(obj) return res end      -(一元负)
  TM_BNOT,  // __bnot(obj) return res end   ~(一元按位取反)
  TM_LT,  // __lt(obj1, obj2) return res end       <
  TM_LE,  // __le(obj1, obj2) return res end       <=
  TM_CONCAT,  // __concat(obj1, obj2) return res end   ..
  TM_CALL,  // __call(obj, ...)       方法调用
  TM_CLOSE, // __close      对象关闭
  TM_N		/* 枚举元素数量 */
} TMS;


/*
** 所有快速访问方法标记为1的掩码
** flag中的任何一个位为1则表示元表没有对应的元方法字段(第7位用于'isrealasize')
*/
#define maskflags	(~(~0u << (TM_EQ + 1))) // 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00111111


/*
** 是否是一个元方法(因为元方法使用原生访问，结果可能会变成一个“empty”/nil)
*/
#define notm(tm)	ttisnil(tm)

/* gfasttm(global_State* g, Table *et, TMS e) */
#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
  ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))

#define fasttm(l,et,e)	gfasttm(G(l), et, e)

#define ttypename(x)	luaT_typenames_[(x) + 1]

LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];)

// 返回给定对象的类型名称
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);

// 从事件表中获取指定事件的元方法
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
// 从给定对象的元表中获取指定事件的元方法
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
                                                       TMS event);
// 初始化元方法系统
LUAI_FUNC void luaT_init (lua_State *L);

/* 调用元方法 调用元方法 f: 元方法, p1: 第一个参数, p2: 第二个参数, p3: 第三个参数 */
LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
                            const TValue *p2, const TValue *p3);
// luaT_callTM 调用一个元方法，传入三个参数，并将结果压入栈中
LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f,
                            const TValue *p1, const TValue *p2, StkId p3);

// 尝试调用二元操作的元方法, p1: 第一个操作数, p2: 第二个操作数, res: 结果位置
LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
                              StkId res, TMS event);
// 尝试调用字符串连接的元方法
LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
// 尝试调用二元关联操作的元方法
LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1,
       const TValue *p2, int inv, StkId res, TMS event);
LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
                               int inv, StkId res, TMS event);
// 尝试调用比较操作元方法
LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
                                const TValue *p2, TMS event);
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
                                 int inv, int isfloat, TMS event);
// 调整可变参数的数量，使其符合函数的预期参数数量
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
                                   CallInfo *ci, const Proto *p);
// 获取可变参数，并将其压入栈中
LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
                                              StkId where, int wanted);


#endif
